package com.coolxiaoyoa.donwload;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.stream.ChunkedWriteHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;

/**
 * @author Kerry on 18/09/29
 */

public class HttpDownloadServer implements Runnable {

    private static Logger logger = LoggerFactory.getLogger(HttpDownloadServer.class);

    private final HttpConfig httpConfig;
    private MainController mainController;


    public HttpDownloadServer(HttpConfig httpConfig) {
        this.httpConfig = httpConfig;
    }

    private void startNetty() throws IOException {

        logger.info("{}", this.httpConfig);

        File baseFolder = new File(httpConfig.getBasePath());
        if (!baseFolder.exists() || !baseFolder.isDirectory()) {
            throw new IOException("Base path is empty or not a folder!" + httpConfig.getBasePath());
        }
        mainController = new MainController(httpConfig);


        EventLoopGroup boss = new NioEventLoopGroup();
        EventLoopGroup work = new NioEventLoopGroup();

        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(boss, work)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        ChannelPipeline pipeline = ch.pipeline();
                        pipeline.addLast("http-decoder", new HttpRequestDecoder());
                        pipeline.addLast("http-aggregator", new HttpObjectAggregator(65535));
                        pipeline.addLast("http-encoder", new HttpResponseEncoder());
                        pipeline.addLast("http-chunk", new ChunkedWriteHandler());
                        pipeline.addLast("http-handler", new HttpDownloadServerHandler(mainController));
                    }
                });
        try {
            ChannelFuture sync = bootstrap.bind(httpConfig.getPort()).sync();
            sync.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            boss.shutdownGracefully();
            work.shutdownGracefully();
        }
    }

    public void run() {
        try {
            startNetty();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
